package zwp.exercise.service.exercisedemo.chapterThree.basicdatatypes;

import java.math.BigDecimal;

/**
 * @Author zwp14
 * @create 2025/10/14 22:10
 * @description 演示浮点数据类型不精确场景
 *
 * 思考：浮点数据类型存在不准确的场景，应该如何避免呢
 */
public class DoubleUnAccurate {
    public static void main(String[] args) {
        // 浮点不精确场景一，无限小数计算：4.35 * 100的结果
        testMethodOne();
        System.out.println("-------------------------------------------------------------");
        // 浮点不精确场景二，结果不相等：计算2.0-1.9的结果
        testMethodTwo();
        System.out.println("-------------------------------------------------------------");
        // 演示如何避免浮点数据类型不准确场景
        testMethodThree();
    }

    /**
     * 演示如何避免浮点数据类型不准确场景
     */
    private static void testMethodThree() {
        // 1.使用BigDecimal进行精确计算
        BigDecimal numOne = new BigDecimal("0.1");
        BigDecimal numTwo = new BigDecimal("0.2");
        BigDecimal numAdd = numOne.add(numTwo);

        System.out.println("输出BigDecimal类型的numOne：" + numOne);
        System.out.println("输出BigDecimal类型的numOne：" + numTwo);
        System.out.println("输出BigDecimal类型的numOne+numTwo：" + numAdd);

        // 2.使用整数代替浮点类型 这里的100代替1.00，20代替0.20
        int intNumOne = 100;
        int intNumTwo = 20;
        int intNumAdd = intNumOne + intNumTwo;
        int intNumAddReal = (intNumOne + intNumTwo)/100;

        System.out.println("输出intNumOne+intNumTwo：" + intNumAdd);
        // 这里又出现了场景1中的问题，目前暂不知道好的解决办法，所以使用整数代替的方法不推荐
        System.out.println("输出替代前（真正想要的值）【存在不精确问题】：" + intNumAddReal);

        // 解决办法：使用格式化输出时控制小数位，前提需要再强转换为双精度类型double
        double intNumAddRealDouble = (double)(intNumOne + intNumTwo)/100;
        System.out.println("输出替代前（真正想要的值）【精确】：" + String.format("%.2f", intNumAddRealDouble));


        // 3.误差范围比较
        double a = 0.1 + 0.2;
        double b = 0.3;
        System.out.println("输出a的值：" + a + "输出b的值：" + b);
        if (Math.abs(a - b) < 1e-10) {
            System.out.println("a ≈ b");
        }

    }

    /**
     * 浮点不精确场景二，结果不相等：计算2.0-1.9的结果
     */
    private static void testMethodTwo() {
        double numOne = 0.1;
        double numTwo = 2.0 - 1.9;
        System.out.println("输出numOne的值：" + numOne);
        System.out.println("输出numTwo的值：" + numTwo);
        System.out.println("判断numOne和numTwo的值是否相等：" + (numOne == numTwo));

        // Math.abs()是取绝对值的方法，1e-6表示1*10的-6次方，是计算机中最小数的概念,（但并不是java语言中最小数）
        double abs = Math.abs(numOne - numTwo);
        boolean bool = abs < (1e-6);
        // 如果两数之差的绝对值小于最小数，则认为这两个数是相等的
        System.out.println("输出numOne和numTwo之差的绝对值abs：" + abs +
                "以及判断其是否小于计算机中最小数【1e-6】：" + bool);
    }

    /**
     * 计算4.35 * 100的结果
     */
    private static void testMethodOne() {
        // 用double 计算4.35 * 100的结果
        double numOne = 4.35 * 100;
        System.out.println("输出double数据类型numOne的值 = " + numOne);

        // 将double类型强制转换为int类型
        int numTwo = (int) numOne;

        System.out.println("numOne强转为int数据类型后的值 = " + numTwo);
        System.out.println("输出numOne四舍五入的值：" + Math.round(numOne));
    }
}
